#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os

from common.common import check_sql_cmd_param
from common.const import SubJobStatusEnum
from common.common_models import SubJobDetails
from common.exception.common_exception import ErrCodeException
from common.security.anonym_utils.anonymity import Anonymity
from generaldb.saphana.restore.saphana_parse_restore_params import SaphanaParseRestoreParam
from generaldb.saphana.restore.saphana_restore_parent import SaphanaRestoreParent
from generaldb.saphana.comm.saphana_const import SaphanaProgressPhase, SaphanaJsonConstant, \
    SaphanaDbActionType, SaphanaConst, SaphanaErrorCode
from generaldb.saphana.comm.saphana_file_operate import log


class SaphanaRestoreTenant(SaphanaRestoreParent):
    def __init__(self, pid, job_id, subjob_id, parse_params_obj: SaphanaParseRestoreParam):
        super(SaphanaRestoreTenant, self).__init__(pid, job_id, subjob_id, parse_params_obj)
        self._restore_progress = 0
        self._max_progress = 0
        self._current_progress = 0
        self._max_phase = 0
        self._current_phase = 0
        self._error_code = 0
        self._error_param_list = []

    def exec_restore_data_cmd(self, copy_path):
        login_db_name = SaphanaConst.SYSTEM_DB if self._saphana_cluster.is_multi_system() else self._sid
        system_db_pwd = SaphanaJsonConstant.SYSTEM_DB_PASSWORD + self._pid
        # 执行恢复命令, 路径中有'\',只能用''保护，不做防注入校验
        restore_cmd = f"recover data for {self._db_name} using file ('{copy_path}/') clear log"
        if not check_sql_cmd_param(self._db_name):
            log.error(f"Invalid dbname:{self._db_name}. {self._parse_param.get_log_common()}")
            return False
        log.info(f"Begin to execute restore cmd: {restore_cmd}")
        ret, output = self._saphana_cluster.execute_query_in_db(
            login_db_name, self._system_db_user, system_db_pwd, restore_cmd, SaphanaDbActionType.PROTECT_CMD)
        if not ret:
            log.error(f"Exec restore cmd failed. out:{output}. {self._parse_param.get_log_common()}")
            self._error_code = SaphanaErrorCode.EXEC_BACKUP_RECOVER_CMD_FAIL
            self._error_param_list = ["recover", Anonymity.process(output)] if output else ["recover", "unknown"]
            return False
        return True

    def exec_restore_log_cmd(self, restore_time, cata_log_path, log_data_path, copy_data_path, backup_id):
        system_db_pwd = SaphanaJsonConstant.SYSTEM_DB_PASSWORD + self._pid
        login_db_name = SaphanaConst.SYSTEM_DB if self._saphana_cluster.is_multi_system() else self._sid
        if not self._check_recover(copy_data_path, log_data_path, cata_log_path, restore_time):
            log.error(f"Check recover failed. {copy_data_path} {log_data_path} {cata_log_path} {restore_time}")
            return False
        # 路径中有'\',只能用''保护，不做防注入校验
        restore_cmd = f"RECOVER DATABASE FOR {self._db_name} UNTIL TIMESTAMP '{restore_time}' CLEAR LOG\
            USING CATALOG PATH ('{cata_log_path}') USING LOG PATH ('{log_data_path}') \
            USING DATA PATH ('{copy_data_path}') USING BACKUP_ID {backup_id}"
        restore_cmd = restore_cmd + " IGNORE DELTA DATA BACKUPS"*self._ignore_delta
        log.info(f"Begin to execute restore cmd: {restore_cmd}")
        ret, output = self._saphana_cluster.execute_query_in_db(login_db_name, self._system_db_user, \
            system_db_pwd, restore_cmd, SaphanaDbActionType.PROTECT_CMD)
        if not ret:
            log.error(f"Exec restore cmd failed. out:{output}. {self._parse_param.get_log_common()}")
            self._error_code = SaphanaErrorCode.EXEC_BACKUP_RECOVER_CMD_FAIL
            self._error_param_list = ["recover", Anonymity.process(output)] if output else ["recover", "unknown"]
            return False
        return True

    def allow_restore(self):
        # 判断是否能登录系统数据库
        if self.is_system_db():
            system_db_pwd = f"{SaphanaJsonConstant.JOB}_{SaphanaJsonConstant.TARGET_ENV}_{SaphanaJsonConstant.AUTH}_" \
                            f"{SaphanaJsonConstant.AUTH_PWD}_{self._pid}"
        else:
            system_db_pwd = SaphanaJsonConstant.SYSTEM_DB_PASSWORD + self._pid
        login_db_name = SaphanaConst.SYSTEM_DB if self._saphana_cluster.is_multi_system() else self._sid
        try:
            ret = self._saphana_cluster.log_specify_database(login_db_name, self._system_db_user, system_db_pwd)
        except ErrCodeException as err:
            self._error_code = SaphanaErrorCode.LOGIN_SYSTEM_DB_ERROR.value
            return False
        if not ret:
            log.error(f"Login database failed. {self._parse_param.get_log_common()}")
            self._error_code = SaphanaErrorCode.LOGIN_SYSTEM_DB_ERROR.value
            return False
        log.info(f"Allow restore in local node success. {self._parse_param.get_log_common()}")
        return True

    def progress_func(self):
        sub_job_details = SubJobDetails(taskId=self._job_id, subTaskId=self._subjob_id,
                                 progress=SaphanaProgressPhase.RUNNING,
                                 taskStatus=SubJobStatusEnum.RUNNING.value).dict(by_alias=True)
        return sub_job_details
